/**
 * 
 */
package belote.service.user;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.SortDirection;

/**
 * @author Gwenn
 * 
 */
public class UserServiceImpl implements UserService {

	// ------------------------------------------------------------------------
	// CONSTANTES
	// ------------------------------------------------------------------------

	private static final String KIND_USER = "User";

	private static final String PROPERTY_PASSWORD = "password";
	private static final String PROPERTY_LOGIN = "login";
	private static final String PROPERTY_MAIL = "email";
	private static final String PROPERTY_CREATION_DATE = "creationDate";
	private static final String PROPERTY_LAST_MODIFICATION_DATE = "lastModificationDate";
	private static final String PROPERTY_LAST_CONNECTION_DATE = "lastConnectionDate";

	// ------------------------------------------------------------------------
	// SERVICES
	// ------------------------------------------------------------------------

	private final DatastoreService datastore;

	// ------------------------------------------------------------------------
	// CONSTRUCTEURS
	// ------------------------------------------------------------------------

	/**
	 * Constructeur par defaut.
	 */
	public UserServiceImpl() {

		datastore = DatastoreServiceFactory.getDatastoreService();
	}

	// ------------------------------------------------------------------------
	// METHODES 'PUBLIC'
	// ------------------------------------------------------------------------

	/**
	 * {@inheritDoc}
	 */
	@Override
	public User select(long pUId) {

		Key key = KeyFactory.createKey(KIND_USER, pUId);

		try {
			Entity entity = datastore.get(key);
			User user = new User();
			entityToObject(entity, user);

			return user;

		} catch (EntityNotFoundException e) {

			return null;
		}
	}

	/**
	 * {@inheritDoc}
	 */
	// @Override
	public long count() {

		Query q = new Query(KIND_USER);
		PreparedQuery pq = datastore.prepare(q);
		return pq.countEntities(FetchOptions.Builder.withDefaults());
	}

	/**
	 * {@inheritDoc}
	 */
	// @Override
	public List<User> selectAll() {

		Query q = new Query(KIND_USER);
		q.addSort(PROPERTY_LOGIN, SortDirection.ASCENDING);

		PreparedQuery pq = datastore.prepare(q);
		List<User> utilisateurs = new ArrayList<User>();
		for (Entity entity : pq.asIterable()) {
			User utilisateur = new User();
			entityToObject(entity, utilisateur);
			utilisateurs.add(utilisateur);
		}
		return utilisateurs;
	}

	/**
	 * {@inheritDoc}
	 */
	// @Override
	public List<User> searchByLogin(String pString) {

		Query q = new Query(KIND_USER);
		q.addSort(PROPERTY_LOGIN, SortDirection.ASCENDING);

		PreparedQuery pq = datastore.prepare(q);
		List<User> utilisateurs = new ArrayList<User>();
		for (Entity entity : pq.asIterable()) {

			if (((String) entity.getProperty(PROPERTY_LOGIN)).contains(pString)) {
				User utilisateur = new User();
				entityToObject(entity, utilisateur);
				utilisateurs.add(utilisateur);
			}
		}
		return utilisateurs;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public User selectByLoginPassword(String pLogin, String pPassword) {

		Query q = new Query(KIND_USER);
		q.addFilter(PROPERTY_LOGIN, FilterOperator.EQUAL, pLogin);
		q.addFilter(PROPERTY_PASSWORD, FilterOperator.EQUAL, pPassword);

		PreparedQuery pq = datastore.prepare(q);
		Entity entity = pq.asSingleEntity();

		if (entity != null) {
			User user = new User();
			entityToObject(entity, user);
			return user;
		}

		return null;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public User selectByLogin(String pLogin) {

		Query q = new Query(KIND_USER);
		q.addFilter(PROPERTY_LOGIN, FilterOperator.EQUAL, pLogin);

		PreparedQuery pq = datastore.prepare(q);
		Entity entity = pq.asSingleEntity();

		if (entity != null) {
			User user = new User();
			entityToObject(entity, user);
			return user;
		}

		return null;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public User selectByEmail(String pEmail) {

		Query q = new Query(KIND_USER);
		q.addFilter(PROPERTY_MAIL, FilterOperator.EQUAL, pEmail);

		PreparedQuery pq = datastore.prepare(q);
		Entity entity = pq.asSingleEntity();

		if (entity != null) {
			User user = new User();
			entityToObject(entity, user);
			return user;
		}

		return null;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isLoginExists(String pLogin) {

		Query q = new Query(KIND_USER).setKeysOnly();
		q.addFilter(PROPERTY_LOGIN, FilterOperator.EQUAL, pLogin);

		PreparedQuery pq = datastore.prepare(q);
		Entity entity = pq.asSingleEntity();

		return (entity != null);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isEmailExists(String pEmail) {

		Query q = new Query(KIND_USER).setKeysOnly();
		q.addFilter(PROPERTY_MAIL, FilterOperator.EQUAL, pEmail);

		PreparedQuery pq = datastore.prepare(q);
		Entity entity = pq.asSingleEntity();

		return (entity != null);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void insert(User pUser) {

		Entity entity = new Entity(KIND_USER);
		objectToEntity(pUser, entity);

		Key key = datastore.put(entity);

		pUser.setId(key.getId());
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void update(User pUser) {

		Key key = KeyFactory.createKey(KIND_USER, pUser.getId());

		try {
			Entity entity = datastore.get(key);
			objectToEntity(pUser, entity);
			datastore.put(entity);

		} catch (EntityNotFoundException e) {
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void delete(long pId) {

		Key key = KeyFactory.createKey(KIND_USER, pId);
		datastore.delete(key);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void activate(long pUID) throws UserServiceException {

		// TODO
	}

	// ------------------------------------------------------------------------
	// METHODES 'PROTECTED'
	// ------------------------------------------------------------------------

	protected void objectToEntity(User pObject, Entity pEntity) {

		pEntity.setProperty(PROPERTY_LOGIN, pObject.getLogin());
		pEntity.setProperty(PROPERTY_PASSWORD, pObject.getPassword());
		pEntity.setProperty(PROPERTY_MAIL, pObject.getEmail());

		pEntity.setProperty(PROPERTY_CREATION_DATE, pObject.getCreationDate());
		pEntity.setProperty(PROPERTY_LAST_MODIFICATION_DATE, pObject.getLastModificationDate());
		pEntity.setProperty(PROPERTY_LAST_CONNECTION_DATE, pObject.getLastConnectionDate());
	}

	protected void entityToObject(Entity pEntity, User pObject) {

		// ID
		pObject.setId(pEntity.getKey().getId());

		// Properties
		pObject.setLogin((String) pEntity.getProperty(PROPERTY_LOGIN));
		pObject.setPassword((String) pEntity.getProperty(PROPERTY_PASSWORD));
		pObject.setEmail((String) pEntity.getProperty(PROPERTY_MAIL));

		pObject.setCreationDate((Date) pEntity.getProperty(PROPERTY_CREATION_DATE));
		pObject.setLastModificationDate((Date) pEntity.getProperty(PROPERTY_LAST_MODIFICATION_DATE));
		pObject.setLastConnectionDate((Date) pEntity.getProperty(PROPERTY_LAST_CONNECTION_DATE));
	}
}
